﻿//***********************************************************************************
// 文件名称：RankManager
// 功能描述：排行榜管理类
// 数据表：
// 作者：liuxiaohu
// 日期：2017/3/13 9:16:20
// 修改记录：
//***********************************************************************************

using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;

namespace GameServer
{
    using MySql.Data.MySqlClient;

    /// <summary>
    /// 排行榜管理类
    /// </summary>
    public class RankManager
    {
        #region 字段

        /// <summary>
        /// 排行榜信息
        /// </summary>
        private Dictionary<Int32, Rank> rankList = new Dictionary<Int32, Rank>();

        /// <summary>
        /// 读写同步锁对象
        /// </summary>
        private static ReaderWriterLockSlim rankListLock = new ReaderWriterLockSlim();

        /// <summary>
        /// 排行榜数据库对象
        /// </summary>
        private RankDB rankDB = new RankDB();

        /// <summary>
        /// 错误信息
        /// </summary>
        private String errorMessage;

        #endregion

        #region 方法

        /// <summary>
        /// 排行榜初始化
        /// </summary>
        /// <returns>初始化结果</returns>
        public bool Init()
        {
            // 从数据库加载排行榜数据
            rankList = rankDB.GetList();

            return true;
        }

        /// <summary>
        /// 将排行榜信息读取到中间变量中并返回
        /// </summary>
        /// <param name="isWritting">是否有写入操作</param>
        /// <returns>排行榜信息</returns>
        public Dictionary<Int32, Rank> GetRankList(Boolean isWritting = true)
        {
            Dictionary<Int32, Rank> tmpRankList = new Dictionary<int, Rank>();

            // 不存在写操作时，直接获取内存中的信息
            if (!isWritting)
            {
                tmpRankList = rankList;
            }
            else
            {
                rankListLock.EnterReadLock();
                try
                {
                    foreach (var rank in rankList)
                    {
                        tmpRankList.Add(rank.Key, rank.Value);
                    }
                }
                finally
                {
                    rankListLock.ExitReadLock();
                }
            }

            return tmpRankList;
        }

        /// <summary>
        /// 获取前20排行榜信息
        /// </summary>
        /// <returns>前20排行榜信息</returns>
        public List<Rank> GetTop20RankList()
        {
            Int32 num = 0;
            List<Rank> list = new List<Rank>();

            // 遍历排行榜中信息
            foreach (KeyValuePair<Int32, Rank> kv in GetRankList())
            {
                list.Add(kv.Value);

                if ((++num) > 20)
                {
                    break;
                }
            }

            return list;
        }

        /// <summary>
        /// 添加玩家到排行榜中
        /// </summary>
        /// <param name="playerId">玩家Id</param>
        /// <param name="rank">玩家排行信息</param>
        /// <returns>添加结果</returns>
        public bool Add(Int32 playerId, Rank rank)
        {
            #region 添加或刷新玩家到排行榜中

            rankListLock.EnterUpgradeableReadLock();

            try
            {
                Boolean isContain = rankList.ContainsKey(playerId);

                rankListLock.EnterWriteLock();

                try
                {
                    // 添加或刷新玩家到排行榜中
                    if (isContain)
                    {
                        rankList[playerId].PlayerScores = rank.PlayerScores;
                    }
                    else
                    {
                        rankList.Add(playerId, rank);
                        rankDB.Add(playerId, rank.PlayerName, rank.PlayerScores);
                    }
                }
                catch (Exception e)
                {
                    errorMessage = String.Format("[添加玩家{0}错误]:{1}", playerId, e.Message);
                    throw new Exception(errorMessage);
                }
                finally
                {
                    rankListLock.ExitWriteLock();
                }
            }
            catch (Exception e)
            {
                errorMessage = String.Format("[操作失败]:{0}", e.Message);
                throw new Exception(errorMessage);
            }
            finally
            {
                rankListLock.ExitUpgradeableReadLock();
            }

            #endregion

            #region 对排行榜中玩家进行排序

            rankListLock.EnterUpgradeableReadLock();

            try
            {
                //根据玩家积分降序排序
                Dictionary<Int32, Rank> dicSort = rankList.OrderByDescending(p => p.Value.PlayerScores).ToDictionary(p => p.Key, o => o.Value);

                rankListLock.EnterWriteLock();

                try
                {
                    rankList.Clear();
                    Int32 rankNum = 0;
                    foreach (KeyValuePair<Int32, Rank> kvp in dicSort)
                    {
                        // 玩家排行从1往下递增
                        kvp.Value.RankNum = ++rankNum;

                        rankList.Add(kvp.Key, kvp.Value);
                        rankDB.Update(kvp.Key, kvp.Value.PlayerScores, kvp.Value.RankNum);
                    }
                }
                catch (Exception e)
                {
                    errorMessage = String.Format("[排行榜排序错误]:{0}", e.Message);
                    throw new Exception(errorMessage);
                }
                finally
                {
                    rankListLock.ExitWriteLock();
                }
            }
            catch (Exception e)
            {
                errorMessage = String.Format("[操作失败]:{0}", e.Message);
                throw new Exception(errorMessage);
            }
            finally
            {
                rankListLock.ExitUpgradeableReadLock();
            }

            #endregion

            return true;
        }

        /// <summary>
        /// 发奖
        /// </summary>
        public void GetReward()
        {
            // 遍历排行榜中的信息
            foreach (var kvp in GetRankList())
            {
                if (kvp.Value.RankNum > 0 && kvp.Value.RankNum <= 10)
                {
                    // 对排行前10的玩家发奖
                    Int32 playerId = kvp.Key;

                    // 通过邮件发奖
                    // 日志记录
                    String comment = String.Format("GetReward:{0}", kvp.Value.PlayerName);
                    LOG.Write(comment);
                    // todo:
                }
            }
        }

        #endregion

        #region 排行榜数据库相关

        private class RankDB : DataBase
        {
            #region sql语句

            /// <summary>
            /// 插入语句
            /// </summary>
            private static String insertStr = @"insert into Rank 
                (PlayerId,PlayerName,PlayerScore,RankNum) 
                values({0},'{1}',{2},{3});";

            /// <summary>
            /// 更新语句
            /// </summary>
            private static String updateStr = "update Rank set PlayerScore = {0},RankNum = {1} where PlayerId = {2};";

            /// <summary>
            /// 查询语句
            /// </summary>
            private static String selectStr = "select * from Rank;";

            #endregion

            #region 方法

            /// <summary>
            /// 添加玩家到数据库中
            /// </summary>
            /// <param name="playerId">玩家Id</param>
            /// <param name="playerName">玩家姓名</param>
            /// <param name="playerScores">玩家积分</param>
            /// <param name="rankNum">玩家排名</param>
            public void Add(Int32 playerId, String playerName, Int32 playerScores, Int32 rankNum = 0)
            {
                string sql = string.Format(insertStr, playerId, playerName, playerScores, rankNum);
                ExecuteNotQuery(sql);
            }

            /// <summary>
            /// 更新数据
            /// </summary>
            /// <param name="playerId">玩家Id</param>
            /// <param name="playerScores">玩家积分</param>
            /// <param name="rankNum">玩家排名</param>
            public void Update(Int32 playerId, Int32 playerScores, Int32 rankNum)
            {
                string sql = string.Format(updateStr, playerScores, rankNum, playerId);
                ExecuteNotQuery(sql);
            }

            /// <summary>
            /// 从数据库中加载数据
            /// </summary>
            /// <returns>数据库中的数据</returns>
            public Dictionary<Int32, Rank> GetList()
            {
                Dictionary<Int32, Rank> list = new Dictionary<Int32, Rank>();

                MySqlDataReader reader = ExecuteQuery(selectStr);
                if (reader != null)
                {
                    // 从数据库中读取排行榜信息
                    while (reader.Read())
                    {
                        Int32 playerId = Convert.ToInt32(reader["PlayerId"]);
                        String playerName = reader["PlayerName"] == null ? "" : reader["PlayerName"].ToString();
                        Int32 playerScores = Convert.ToInt32(reader["PlayerScore"]);
                        Int32 rankNum = Convert.ToInt32(reader["RankNum"]);

                        list.Add(playerId, new Rank(playerName, playerScores, rankNum));
                    }
                }

                return list;
            }

            #endregion
        }

        #endregion
    }
}